/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.uml;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.print.PageFormat;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import org.acm.seguin.awt.ExceptionPrinter;
import org.acm.seguin.ide.common.ClassListPanel;
import org.acm.seguin.io.Saveable;
import org.acm.seguin.summary.PackageSummary;
import org.acm.seguin.summary.TypeSummary;
import org.acm.seguin.uml.line.AssociationRelationship;
import org.acm.seguin.uml.line.LineMouseAdapter;
import org.acm.seguin.uml.line.LinedPanel;
import org.acm.seguin.uml.line.SegmentedLine;
import org.acm.seguin.uml.line.Vertex;
import org.acm.seguin.uml.print.UMLPagePrinter;
import org.acm.seguin.util.FileSettings;
import org.acm.seguin.util.MissingSettingsException;
/**
* Draws a UML diagram for all the classes in a package
*
*@author Chris Seguin
*/
public class UMLPackage extends LinedPanel implements Saveable {
// Instance Variables
private PackageSummary summary;
private SegmentedLine currentLine = null;
private boolean hasChanged;
private String packageName;
private JScrollPane scrollPane;
private ClassListPanel classListPanel = null;
private boolean first = false;
private boolean loading = false;
/**
* Constructor for UMLPackage
*
*@param packageSummary the summary of the package
*/
public UMLPackage(PackageSummary packageSummary) {
// Initialize the instance variables
defaultValues();
setSummary(packageSummary);
// Don't use a layout manager
setLayout(null);
// Load the summaries
(new PackageLoader(this)).start(summary);
// Reset the size
setSize(getPreferredSize());
addMouseAdapter();
}
/**
* Constructor for UMLPackage
*
*@param filename the name of the file
*/
public UMLPackage(String filename) {
// Initialize the instance variables
defaultValues();
// Don't use a layout manager
setLayout(null);
// Load the summaries
(new PackageLoader(this)).start(filename);
// Reset the size
setSize(getPreferredSize());
addMouseAdapter();
}
/**
* Constructor for UMLPackage
*
*@param input the input stream
*/
public UMLPackage(InputStream input) {
// Initialize the instance variables
defaultValues();
// Don't use a layout manager
setLayout(null);
// Load the summaries
(new PackageLoader(this)).start(input);
// Reset the size
setSize(getPreferredSize());
addMouseAdapter();
}
/**
* Sets the Dirty attribute of the UMLPackage object
*/
public void setDirty() {
hasChanged = true;
}
/**
* Sets the ScrollPane attribute of the UMLPackage object
*
*@param value The new ScrollPane value
*/
public void setScrollPane(JScrollPane value) {
scrollPane = value;
}
/**
* Sets the class list panel
*
*@param value the new list
*/
public void setClassListPanel(ClassListPanel value) {
classListPanel = value;
first = true;
}
/**
* Sets the loading value
*
*@param value The new Loading value
*/
public void setLoading(boolean value) {
loading = value;
}
/**
* Gets the PackageName attribute of the UMLPackage object
*
*@return The PackageName value
*/
public String getPackageName() {
return packageName;
}
/**
* Get the components that are UMLTypes
*
*@return Description of the Returned Value
*/
public UMLType[] getTypes() {
// Instance Variables
Component[] children = getComponents();
int last = children.length;
int count = 0;
// Count the UMLTypes
for (int ndx = 0; ndx < last; ndx++) {
if (children[ndx] instanceof UMLType) {
count++;
}
}
// Count the UMLTypes
UMLType[] results = new UMLType[count];
int item = 0;
for (int ndx = 0; ndx < last; ndx++) {
if (children[ndx] instanceof UMLType) {
results[item] = (UMLType) children[ndx];
item++;
}
}
// Return the result
return results;
}
/**
* Returns the minimum size
*
*@return The size
*/
public Dimension getMinimumSize() {
return getPreferredSize();
}
/**
* Returns the preferred size
*
*@return The size
*/
public Dimension getPreferredSize() {
// Initialize local variables
int wide = 10;
int high = 10;
Component[] children = getComponents();
int last = children.length;
// Deselect the children
for (int ndx = 0; ndx < last; ndx++) {
Rectangle bounds = children[ndx].getBounds();
wide = Math.max(wide, 20 + bounds.x + bounds.width);
high = Math.max(high, 20 + bounds.y + bounds.height);
}
return new Dimension(wide, high);
}
/**
* Get the summary
*
*@return The package summary
*/
public PackageSummary getSummary() {
return summary;
}
/**
* Gets the File attribute of the UMLPackage object
*
*@return The File value
*/
public File getFile() {
return (new PackageLoader(this)).getFile();
}
/**
* Gets the Dirty attribute of the UMLPackage object
*
*@return The Dirty value
*/
public boolean isDirty() {
return hasChanged;
}
/**
* Determines the title
*
*@return the title
*/
public String getTitle() {
return ("UML Diagram for " + packageName);
}
/**
* Remove the association
*
*@param field Description of Parameter
*/
public void removeAssociation(UMLField field) {
Iterator iter = getLines();
while (iter.hasNext()) {
Object next = iter.next();
if (next instanceof AssociationRelationship) {
AssociationRelationship assoc = (AssociationRelationship) next;
if (assoc.getField().equals(field)) {
assoc.delete();
iter.remove();
return;
}
}
}
}
/**
* Paint this object
*
*@param g the graphics object
*/
public void paint(Graphics g) {
setBackground(Color.lightGray);
g.setColor(Color.lightGray);
Dimension size = getSize();
g.fillRect(0, 0, size.width, size.height);
// Draw the grid
PageFormat pf = UMLPagePrinter.getPageFormat(false);
if (pf != null) {
int pageHeight = (int) UMLPagePrinter.getPageHeight();
int pageWidth = (int) UMLPagePrinter.getPageWidth();
g.setColor(Color.gray);
for (int x = pageWidth; x < size.width; x += pageWidth) {
g.drawLine(x, 0, x, size.height);
}
for (int y = pageHeight; y < size.width; y += pageHeight) {
g.drawLine(0, y, size.width, y);
}
}
// Abort once we are loading
if (loading) {
return;
}
// Draw the segmented lines
Iterator iter = getLines();
while (iter.hasNext()) {
((SegmentedLine) iter.next()).paint(g);
}
// Draw the components
paintChildren(g);
}
/**
* Print this object
*
*@param g the graphics object
*@param x the x coordinate
*@param y the y coordinate
*/
public void print(Graphics g, int x, int y) {
Component[] children = getComponents();
int last = children.length;
for (int ndx = 0; ndx < last; ndx++) {
if (children[ndx] instanceof UMLType) {
Point pt = children[ndx].getLocation();
((UMLType) children[ndx]).print(g, x + pt.x, y + pt.y);
}
else if (children[ndx] instanceof UMLLine) {
Point pt = children[ndx].getLocation();
((UMLLine) children[ndx]).print(g, x + pt.x, y + pt.y);
}
}
Iterator iter = getLines();
while (iter.hasNext()) {
((SegmentedLine) iter.next()).paint(g);
}
}
/**
* Reloads the UML class diagrams
*/
public void reload() {
// Save the image
try {
save();
}
catch (IOException ioe) {
ExceptionPrinter.print(ioe);
}
// Reload it
(new PackageLoader(this)).start(summary);
// Reset the size
setSize(getPreferredSize());
reset();
// Nothing has changed
hasChanged = false;
}
/**
* Description of the Method
*/
public void clear() {
removeAll();
super.clear();
}
/**
* Determine what you hit
*
*@param actual The hit location
*/
public void hit(Point actual) {
currentLine = null;
Iterator iter = getLines();
while ((currentLine == null) && iter.hasNext()) {
SegmentedLine next = (SegmentedLine) iter.next();
if (next.hit(actual)) {
currentLine = next;
}
}
while (iter.hasNext()) {
SegmentedLine next = (SegmentedLine) iter.next();
next.select(false);
}
repaint();
}
/**
* Dragging a segmented line point
*
*@param actual The mouse's current location
*/
public void drag(Point actual) {
if (currentLine != null) {
currentLine.drag(actual);
repaint();
}
}
/**
* User dropped an item
*/
public void drop() {
if (currentLine != null) {
currentLine.drop();
hasChanged = true;
currentLine = null;
}
reset();
}
/**
* Save the files
*
*@exception IOException Description of Exception
*/
public void save() throws IOException {
// Make sure we have something that has changed
if (!hasChanged) {
return;
}
// Local Variables
Component[] children = getComponents();
int last = children.length;
File dir = summary.getDirectory();
File outputFile;
if (dir == null) {
dir = new File(System.getProperty("user.home") +
File.separator + ".Refactory" +
File.separator + "UML");
dir.mkdirs();
outputFile = new File(dir +
File.separator + summary.getName() + ".uml");
}
else {
outputFile = new File(summary.getDirectory(), "package.uml");
}
PrintWriter output = new PrintWriter(
new FileWriter(outputFile));
output.println("V[1.1:" + summary.getName() + "]");
// Save the line segments
Iterator iter = getLines();
while (iter.hasNext()) {
((SegmentedLine) iter.next()).save(output);
}
// Save the types
for (int ndx = 0; ndx < last; ndx++) {
if (children[ndx] instanceof UMLType) {
((UMLType) children[ndx]).save(output);
}
}
output.close();
// Nothing has changed
hasChanged = false;
}
/**
* Tells the scrollbar to jump to this location
*
*@param type Description of Parameter
*/
public void jumpTo(TypeSummary type) {
UMLType umlType = findType(type);
if (umlType == null) {
return;
}
Point pt = umlType.getLocation();
JScrollBar horiz = scrollPane.getHorizontalScrollBar();
horiz.setValue(pt.x - 10);
JScrollBar vert = scrollPane.getVerticalScrollBar();
vert.setValue(pt.y - 10);
}
/**
* Find the type based on a summary
*
*@param searching the variable we are searching for
*@return the UML type object
*/
protected UMLType findType(TypeSummary searching) {
// Instance Variables
Component[] children = getComponents();
int last = children.length;
int count = 0;
TypeSummary current;
if (searching == null) {
return null;
}
// Count the UMLTypes
for (int ndx = 0; ndx < last; ndx++) {
if (children[ndx] instanceof UMLType) {
current = ((UMLType) children[ndx]).getSummary();
if (searching.equals(current)) {
return (UMLType) children[ndx];
}
}
}
// Not found
return null;
}
/**
* Find the type based on a id code
*
*@param id the code we are searching for
*@return the UML type object
*/
protected UMLType find(String id) {
// Instance Variables
Component[] children = getComponents();
int last = children.length;
int count = 0;
String current;
if (id == null) {
return null;
}
// Find the id that matches
for (int ndx = 0; ndx < last; ndx++) {
if (children[ndx] instanceof UMLType) {
current = ((UMLType) children[ndx]).getID();
if (id.equals(current)) {
return (UMLType) children[ndx];
}
}
}
// Not found
return null;
}
/**
* Find the type based on a id code
*
*@param panel1 Description of Parameter
*@param panel2 Description of Parameter
*@return the UML type object
*/
protected SegmentedLine find(String panel1, String panel2) {
UMLType first = find(panel1);
UMLType second = find(panel2);
if ((first == null) || (second == null)) {
return null;
}
Iterator iter = getLines();
while (iter.hasNext()) {
SegmentedLine line = (SegmentedLine) iter.next();
if (line.match(first, second)) {
return line;
}
}
return null;
}
/**
* Sets the summary
*
*@param value The package summary
*/
void setSummary(PackageSummary value) {
summary = value;
if (summary != null)
packageName = summary.getName();
}
/**
* Tells the class list panel to laod itself
*/
void updateClassListPanel() {
if (classListPanel == null) {
return;
}
if (first) {
first = false;
return;
}
classListPanel.load(summary);
}
/**
* Set up the default values
*/
private void defaultValues() {
packageName = "Unknown Package";
hasChanged = false;
try {
FileSettings umlBundle = FileSettings.getSettings("Refactory", "uml");
umlBundle.setContinuallyReload(true);
Vertex.setVertexSize(umlBundle.getInteger("sticky.point.size"));
Vertex.setNear(umlBundle.getDouble("halo.size"));
}
catch (MissingSettingsException mse) {
Vertex.setNear(3.0);
Vertex.setVertexSize(5);
}
}
/**
* Adds a feature to the MouseAdapter attribute of the UMLPackage object
*/
private void addMouseAdapter() {
LineMouseAdapter adapter = new LineMouseAdapter(this);
addMouseListener(adapter);
addMouseMotionListener(adapter);
}
/**
* Resets the scroll panes
*/
private void reset() {
if (scrollPane == null) {
repaint();
}
else {
Dimension panelSize = getPreferredSize();
JViewport view = scrollPane.getViewport();
Dimension viewSize = view.getSize();
setSize(Math.max(panelSize.width, viewSize.width),
Math.max(panelSize.height, viewSize.height));
view.setViewSize(getSize());
scrollPane.repaint();
}
}
}